package com.demo.uid.service;

import com.demo.uid.algorithm.SnowFlake;
import com.demo.uid.constant.ConfigConstant;
import com.demo.uid.properties.UidGroupProperties;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Slf4j
@Service
public class SnowFlakeService {

    @Resource
    private UidGroupProperties uidGroupProperties;

    private Map<String, SnowFlake> snowFlakeMap = new HashMap<>();

    private SnowFlake snowFlake;

    public synchronized void init(Integer machineId) {
        Map<String, List<String>> map = uidGroupProperties.getMap();
        if (map != null) {
            for (Map.Entry<String, List<String>> entry : map.entrySet()) {
                List<String> list = entry.getValue();
                if (CollectionUtils.isEmpty(list)) {
                    continue;
                }

                for (String s : list) {
                    SnowFlake snowFlake = new SnowFlake(machineId, ConfigConstant.dataCenterId);
                    snowFlakeMap.putIfAbsent(genKey(entry.getKey(), s), snowFlake);
                }
            }

            removeInvalidKey(snowFlakeMap, map);
        }
        log.info("初始化snowFlakeMap：{}", snowFlakeMap);

        if (snowFlake == null) {
            snowFlake = new SnowFlake(machineId, ConfigConstant.dataCenterId);
        }
    }

    public void updateSnowFlakeMachineId(Integer machineId) {
        snowFlakeMap.values().forEach(s -> s.setWorkerId(machineId.longValue()));
    }

    public long getId(String prefix, String biz) {
        return snowFlakeMap.get(genKey(prefix, biz)).nextId();
    }

    public long getGlobalId() {
        return snowFlake.nextId();
    }

    private String genKey(String prefix, String biz) {
        return prefix + "_" + biz;
    }

    private void removeInvalidKey(Map<String, SnowFlake> snowFlakeMap, Map<String, List<String>> configMap) {
        // 不能直接用keySet方法执行removeAll，执行removeAll会把Map对象里的key也remove
        Set<String> sonwFlakeSet = Sets.newHashSet(snowFlakeMap.keySet());
        Set<String> configSet = Sets.newHashSet();
        configMap.forEach((key, value) -> {
            value.forEach(s -> configSet.add(genKey(key, s)));
        });

        sonwFlakeSet.removeAll(configSet);
        sonwFlakeSet.forEach(key -> snowFlakeMap.remove(key));
    }
}
